{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "参考：\n",
    "- <https://www.cnblogs.com/huchong/p/8244279.html>\n",
    "- <https://segmentfault.com/a/1190000016497271>\n",
    "\n",
    "\n",
    "单例模式\n",
    "====\n",
    "\n",
    "**单例模式（Singleton Pattern）**是一种常用的软件设计模式，该模式的主要目的是确保**某一个类只有一个实例存在**。当你希望在整个系统中，某个类只能出现一个实例时，单例对象就能派上用场。\n",
    "\n",
    "比如，某个服务器程序的配置信息存放在一个文件中，客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间，有很多地方都需要使用配置文件的内容，也就是说，很多地方都需要创建 AppConfig 对象的实例，这就导致系统中存在多个 AppConfig 的实例对象，而这样会严重浪费内存资源，尤其是在配置文件内容很多的情况下。事实上，类似 AppConfig 这样的类，我们希望在程序运行期间只存在一个实例对象。\n",
    "\n",
    "在 Python 中，我们可以用多种方法来实现单例模式\n",
    "\n",
    "\n",
    "实现单例模式的几种方式\n",
    "==========="
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用模块\n",
    "\n",
    "其实，**Python 的模块就是天然的单例模式**，因为模块在第一次导入时，会生成 `.pyc` 文件，当第二次导入时，就会直接加载 `.pyc` 文件，而不会再次执行模块代码。因此，我们只需把相关的函数和数据定义在一个模块中，就可以获得一个单例对象了。如果我们真的想要一个单例类，可以考虑这样做：\n",
    "\n",
    "**mysingleton.py**\n",
    "\n",
    "```py\n",
    "class Singleton(object):\n",
    "    def foo(self):\n",
    "        pass\n",
    "singleton1 = Singleton()\n",
    "```\n",
    "\n",
    "将上面的代码保存在文件 `mysingleton.py` 中，要使用时，直接在其他任意文件中导入此文件中的对象，这个对象即是单例模式的对象，在其任一个模块中改变时，其他模块中的引用也会跟着改变。（引用类型）\n",
    "\n",
    "```py\n",
    "from mysingleton import singleton1\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 使用类\n",
    "\n",
    "### 简洁方式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```py\n",
    "class Singleton(object):\n",
    "\n",
    "    def __init__(self):\n",
    "        pass\n",
    "\n",
    "    @classmethod\n",
    "    def instance(cls, *args, **kwargs):\n",
    "        if not hasattr(Singleton, \"_instance\"):\n",
    "            Singleton._instance = Singleton(*args, **kwargs)\n",
    "        return Singleton._instance\n",
    "```\n",
    "一般情况，大家以为这样就完成了单例模式，但是这样当使用多线程时会存在问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0  <__main__.Singleton object at 0x000002351FEF94E0>\n",
      "\n",
      "1  <__main__.Singleton object at 0x000002351FEF94E0>\n",
      "\n",
      "2  <__main__.Singleton object at 0x000002351FEF94E0>\n",
      "\n",
      "3  <__main__.Singleton object at 0x000002351FEF94E0>\n",
      "\n",
      "4  <__main__.Singleton object at 0x000002351FEF94E0>\n",
      "\n",
      "5  <__main__.Singleton object at 0x000002351FEF94E0>\n",
      "\n",
      "6  <__main__.Singleton object at 0x000002351FEF94E0>\n",
      "\n",
      "7  <__main__.Singleton object at 0x000002351FEF94E0>\n",
      "\n",
      "8  <__main__.Singleton object at 0x000002351FEF94E0>\n",
      "\n",
      "9  <__main__.Singleton object at 0x000002351FEF94E0>\n",
      "\n"
     ]
    }
   ],
   "source": [
    "class Singleton(object):\n",
    "\n",
    "    def __init__(self):\n",
    "        pass\n",
    "\n",
    "    @classmethod\n",
    "    def instance(cls, *args, **kwargs):\n",
    "        if not hasattr(Singleton, \"_instance\"):\n",
    "            Singleton._instance = Singleton(*args, **kwargs)\n",
    "        return Singleton._instance\n",
    "\n",
    "import threading\n",
    "\n",
    "def task(arg):\n",
    "    obj = Singleton.instance()\n",
    "    print('%d  %s\\n' %(arg, obj))\n",
    "\n",
    "for i in range(10):\n",
    "    t = threading.Thread(target=task, args=[i,])\n",
    "    t.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br>\n",
    "看起来也没有问题，那是因为执行速度过快，如果在 init 方法中有一些 IO 操作，就会发现问题了，下面我们通过 time.sleep 模拟\n",
    "\n",
    "我们在上面__init__方法中加入以下代码：\n",
    "\n",
    "```py\n",
    "def __init__(self):\n",
    "    import time\n",
    "    time.sleep(1)\n",
    "```\n",
    "\n",
    "重新执行程序后，结果如下"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0  <__main__.Singleton object at 0x000002351FF71F98>\n",
      "\n",
      "3  <__main__.Singleton object at 0x000002351FE40F28>\n",
      "\n",
      "6  <__main__.Singleton object at 0x000002351FBD5F60>\n",
      "\n",
      "2  <__main__.Singleton object at 0x000002351FE408D0>\n",
      "\n",
      "7  <__main__.Singleton object at 0x000002351FEF9550>\n",
      "\n",
      "8  <__main__.Singleton object at 0x000002351FEF9898>\n",
      "\n",
      "1  <__main__.Singleton object at 0x000002351FE40F98>\n",
      "\n",
      "9  <__main__.Singleton object at 0x000002351FEF94A8>\n",
      "\n",
      "5  <__main__.Singleton object at 0x000002351FF65AC8>\n",
      "\n",
      "4  <__main__.Singleton object at 0x000002351FF40358>\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "import threading\n",
    "\n",
    "class Singleton(object):\n",
    "\n",
    "    def __init__(self):\n",
    "        time.sleep(1)\n",
    "\n",
    "    @classmethod\n",
    "    def instance(cls, *args, **kwargs):\n",
    "        if not hasattr(Singleton, \"_instance\"):\n",
    "            Singleton._instance = Singleton(*args, **kwargs)\n",
    "        return Singleton._instance\n",
    "\n",
    "\n",
    "def task(arg):\n",
    "    obj = Singleton.instance()\n",
    "    print('%d  %s\\n' %(arg, obj))\n",
    "\n",
    "for i in range(10):\n",
    "    t = threading.Thread(target=task,args=[i,])\n",
    "    t.start()\n",
    "\n",
    "time.sleep(15)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**问题出现了！按照以上方式创建的单例，无法支持多线程**\n",
    "\n",
    "**解决办法：加锁！**未加锁部分并发执行, 加锁部分串行执行, 速度降低, 但是保证了数据安全"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 线程安全方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "new\n",
      "0  <__main__.Singleton object at 0x00000287FFD4D550>\n",
      "1  <__main__.Singleton object at 0x00000287FFD4D550>\n",
      "\n",
      "\n",
      "2  <__main__.Singleton object at 0x00000287FFD4D550>\n",
      "3  <__main__.Singleton object at 0x00000287FFD4D550>\n",
      "4  <__main__.Singleton object at 0x00000287FFD4D550>\n",
      "\n",
      "\n",
      "\n",
      "5  <__main__.Singleton object at 0x00000287FFD4D550>\n",
      "6  <__main__.Singleton object at 0x00000287FFD4D550>\n",
      "7  <__main__.Singleton object at 0x00000287FFD4D550>\n",
      "\n",
      "8  <__main__.Singleton object at 0x00000287FFD4D550>\n",
      "\n",
      "\n",
      "\n",
      "9  <__main__.Singleton object at 0x00000287FFD4D550>\n",
      "\n",
      "<__main__.Singleton object at 0x00000287FFD4D550>\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "import threading\n",
    "\n",
    "class Singleton(object):\n",
    "    _instance_lock = threading.Lock()\n",
    "\n",
    "    def __init__(self):\n",
    "        print('new')\n",
    "        time.sleep(1)\n",
    "\n",
    "    @classmethod\n",
    "    def instance(cls, *args, **kwargs):\n",
    "        with Singleton._instance_lock:\n",
    "            if not hasattr(Singleton, \"_instance\"):\n",
    "                Singleton._instance = Singleton(*args, **kwargs)\n",
    "        return Singleton._instance\n",
    "\n",
    "\n",
    "def task(arg):\n",
    "    obj = Singleton.instance()\n",
    "    print('%d  %s\\n' %(arg, obj))\n",
    "    \n",
    "for i in range(10):\n",
    "    t = threading.Thread(target=task,args=[i,])\n",
    "    t.start()\n",
    "    \n",
    "time.sleep(15)\n",
    "obj = Singleton.instance()\n",
    "print(obj)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 💊进一步优化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这样就差不多了，但是还是有一点小问题，就是当程序执行时，执行了 time.sleep(20) 后，下面实例化对象时，此时已经是单例模式了，但我们还是加了锁，这样不太好，再进行一些优化，把 intance 方法，改成下面的这样就行：\n",
    "\n",
    "```py\n",
    "@classmethod\n",
    "def instance(cls, *args, **kwargs):\n",
    "    if not hasattr(Singleton, \"_instance\"):\n",
    "        with Singleton._instance_lock:\n",
    "            if not hasattr(Singleton, \"_instance\"):\n",
    "                Singleton._instance = Singleton(*args, **kwargs)\n",
    "    return Singleton._instance\n",
    "```\n",
    "\n",
    "这样，一个可以支持多线程的单例模式就完成了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0  <__main__.Singleton object at 0x000002351FE631D0>\n",
      "1  <__main__.Singleton object at 0x000002351FE631D0>\n",
      "\n",
      "2  <__main__.Singleton object at 0x000002351FE631D0>\n",
      "\n",
      "3  <__main__.Singleton object at 0x000002351FE631D0>\n",
      "\n",
      "4  <__main__.Singleton object at 0x000002351FE631D0>\n",
      "\n",
      "5  <__main__.Singleton object at 0x000002351FE631D0>\n",
      "\n",
      "6  <__main__.Singleton object at 0x000002351FE631D0>\n",
      "\n",
      "7  <__main__.Singleton object at 0x000002351FE631D0>\n",
      "\n",
      "8  <__main__.Singleton object at 0x000002351FE631D0>\n",
      "\n",
      "9  <__main__.Singleton object at 0x000002351FE631D0>\n",
      "\n",
      "\n",
      "<__main__.Singleton object at 0x000002351FE631D0>\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "import threading\n",
    "\n",
    "class Singleton(object):\n",
    "    _instance_lock = threading.Lock()\n",
    "\n",
    "    def __init__(self):\n",
    "        time.sleep(1)\n",
    "\n",
    "    @classmethod\n",
    "    def instance(cls, *args, **kwargs):\n",
    "        if not hasattr(Singleton, \"_instance\"):\n",
    "            with Singleton._instance_lock:\n",
    "                if not hasattr(Singleton, \"_instance\"):\n",
    "                    Singleton._instance = Singleton(*args, **kwargs)\n",
    "        return Singleton._instance\n",
    "\n",
    "\n",
    "def task(arg):\n",
    "    obj = Singleton.instance()\n",
    "    print('%d  %s\\n' %(arg, obj))\n",
    "    \n",
    "for i in range(10):\n",
    "    t = threading.Thread(target=task,args=[i,])\n",
    "    t.start()\n",
    "    \n",
    "time.sleep(15)\n",
    "obj = Singleton.instance()\n",
    "print(obj)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<br>\n",
    "\n",
    "## 使用函数装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def Singleton(cls):\n",
    "    _instance = {}\n",
    "\n",
    "    def _singleton(*args, **kargs):\n",
    "        if cls not in _instance:\n",
    "            _instance[cls] = cls(*args, **kargs)\n",
    "        return _instance[cls]\n",
    "\n",
    "    return _singleton\n",
    "\n",
    "\n",
    "@Singleton\n",
    "class A(object):\n",
    "\n",
    "    def __init__(self, x=0):\n",
    "        self.x = x\n",
    "\n",
    "\n",
    "a1 = A(2)\n",
    "a2 = A(3)\n",
    "a1 is a2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "代码中比较巧妙的一点是:\n",
    "\n",
    "```py\n",
    "_instance = {}\n",
    "```\n",
    "\n",
    "使用不可变的 **类地址** 作为键，其实例作为值，每次创造实例时，首先查看该类是否存在实例，存在的话直接返回该实例即可，否则新建一个实例并存放在字典中。\n",
    "\n",
    "**但是在未加锁的情况下也是不安全的。**\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用类装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "class Singleton(object):\n",
    "    _instance = {}\n",
    "    \n",
    "    def __init__(self, cls):\n",
    "        self._cls = cls\n",
    "\n",
    "    def __call__(self):\n",
    "        if self._cls not in self._instance:\n",
    "            self._instance[self._cls] = self._cls()\n",
    "        return self._instance[self._cls]\n",
    "\n",
    "\n",
    "@Singleton\n",
    "class Cls2(object):\n",
    "    def __init__(self):\n",
    "        pass\n",
    "\n",
    "\n",
    "cls1 = Cls2()\n",
    "cls2 = Cls2()\n",
    "cls3 = Cls2()\n",
    "print(id(cls1) == id(cls2))\n",
    "print(cls1 is cls3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同时，由于是面对对象的，这里还可以这么用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "class Cls3():\n",
    "    pass\n",
    "\n",
    "Cls3 = Singleton(Cls3)\n",
    "cls3 = Cls3()\n",
    "cls4 = Cls3()\n",
    "print(id(cls3) == id(cls4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用 类装饰器实现单例的原理和 函数装饰器 实现的原理相似，理解了上文，再理解这里应该不难。\n",
    "\n",
    "<br>\n",
    "\n",
    "**注意：这种方式实现的单例模式，使用时会有限制，以后实例化必须通过 `obj = Singleton.instance()`，如果用 `obj=Singleton()` , 这种方式得到的不是单例**\n",
    "\n",
    "**在未加锁的情况下也是不安全的。**\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## New、Metaclass 关键字\n",
    "\n",
    "在接着说另外两种方法之前，需要了解在 Python 中一个类和一个实例是通过哪些方法以怎样的顺序被创造的。\n",
    "\n",
    "简单来说， 元类 ( metaclass ) 可以通过方法 metaclass 创造了 类(class) ，而 类(class) 通过方法 new 创造了 实例(instance) 。\n",
    "\n",
    "在单例模式应用中，在创造类的过程中或者创造实例的过程中稍加控制达到最后产生的实例都是一个对象的目的。\n",
    "\n",
    "本文主讲单例模式，所以对这个 topic 只会点到为止，有感兴趣的同学可以在网上搜索相关内容，几篇参考文章：\n",
    "\n",
    "- [What are metaclasses in Python?](https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python)\n",
    "- [python-\\__new__-magic-method-explained](http://howto.lintel.in/python-__new__-magic-method-explained/)\n",
    "- [Why is __init__() always called after __new__()?](https://stackoverflow.com/questions/674304/why-is-init-always-called-after-new)\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基于`__new__`方法实现\n",
    "\n",
    "（推荐使用，方便）\n",
    "\n",
    "通过上面例子，我们可以知道，当我们实现单例时，**为了保证线程安全需要在内部加入锁**\n",
    "\n",
    "我们知道，当我们实例化一个对象时，是**先执行了类的`__new__`方法**（我们没写时，默认调用 `object.__new__`），**实例化对象**；然后**再执行类的`__init__`方法**，对这个对象进行初始化，所以我们可以基于这个，实现单例模式,\n",
    "\n",
    "**但是 `__init__()` 方法还是每次都会执行**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "new\n",
      "new\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "import threading\n",
    "\n",
    "# Method 1:\n",
    "# class Single(object):\n",
    "#     _instance = None\n",
    "#     def __new__(cls, *args, **kw):\n",
    "#         if cls._instance is None:\n",
    "#             cls._instance = object.__new__(cls, *args, **kw)\n",
    "#         return cls._instance\n",
    "#     def __init__(self):\n",
    "#         pass\n",
    "\n",
    "# Method 2:\n",
    "class Singleton(object):\n",
    "    _instance_lock = threading.Lock()\n",
    "\n",
    "    def __init__(self):\n",
    "        print('new')\n",
    "        pass\n",
    "\n",
    "    def __new__(cls, *args, **kwargs):\n",
    "        if not hasattr(Singleton, \"_instance\"):\n",
    "            with Singleton._instance_lock:\n",
    "                if not hasattr(Singleton, \"_instance\"):\n",
    "                    Singleton._instance = object.__new__(cls)\n",
    "        return Singleton._instance\n",
    "\n",
    "\n",
    "obj1 = Singleton()\n",
    "obj2 = Singleton()\n",
    "print(obj1 is obj2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0  <__main__.Singleton object at 0x000002352F813F60>\n",
      "\n",
      "1  <__main__.Singleton object at 0x000002352F813F60>\n",
      "\n",
      "2  <__main__.Singleton object at 0x000002352F813F60>\n",
      "3  <__main__.Singleton object at 0x000002352F813F60>\n",
      "\n",
      "\n",
      "4  <__main__.Singleton object at 0x000002352F813F60>\n",
      "\n",
      "5  <__main__.Singleton object at 0x000002352F813F60>\n",
      "\n",
      "6  <__main__.Singleton object at 0x000002352F813F60>\n",
      "\n",
      "7  <__main__.Singleton object at 0x000002352F813F60>\n",
      "\n",
      "8  <__main__.Singleton object at 0x000002352F813F60>\n",
      "\n",
      "9  <__main__.Singleton object at 0x000002352F813F60>\n",
      "\n"
     ]
    }
   ],
   "source": [
    "def task(arg):\n",
    "    obj = Singleton()\n",
    "    print('%d  %s\\n' %(arg, obj))\n",
    "\n",
    "\n",
    "for i in range(10):\n",
    "    t = threading.Thread(target=task, args=[i, ])\n",
    "    t.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "采用这种方式的单例模式，以后实例化对象时，和平时实例化对象的方法一样 `obj = Singleton()`\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基于 metaclass 方式实现\n",
    "\n",
    "### 相关知识\n",
    "\n",
    "1. 类由type创建，创建类时，type的`__init__`方法自动执行，`类()` 执行type的 `__call__`方法(类的`__new__`方法,类的`__init__`方法)\n",
    "2. 对象由类创建，创建对象时，类的`__init__`方法自动执行，`对象()` 执行类的 `__call__` 方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Foo:\n",
    "    def __init__(self):\n",
    "        pass\n",
    "\n",
    "    def __call__(self, *args, **kwargs):\n",
    "        pass\n",
    "\n",
    "    \n",
    "# 执行type的 __call__ 方法，调用 Foo类（是type的对象）的 __new__方法，\n",
    "# 用于创建对象，然后调用 Foo类（是type的对象）的 __init__方法，用于对对象初始化。\n",
    "obj = Foo()\n",
    "\n",
    "\n",
    "obj()    # 执行Foo的 __call__ 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 元类的使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cls <class '__main__.Foo'>\n"
     ]
    }
   ],
   "source": [
    "class SingletonType(type):\n",
    "    \n",
    "    def __init__(self, *args, **kwargs):\n",
    "        super(SingletonType, self).__init__(*args, **kwargs)\n",
    "\n",
    "    def __call__(cls, *args, **kwargs):  # 这里的cls，即Foo类\n",
    "        print('cls', cls)\n",
    "        obj = cls.__new__(cls, *args, **kwargs)\n",
    "        cls.__init__(obj, *args, **kwargs)  # Foo.__init__(obj)\n",
    "        return obj\n",
    "\n",
    "\n",
    "class Foo(metaclass=SingletonType):  # 指定创建Foo的type为SingletonType\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def __new__(cls, *args, **kwargs):\n",
    "        return object.__new__(cls)\n",
    "\n",
    "\n",
    "obj1 = Foo('Foo1')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br>\n",
    "\n",
    "### 使用 type 创造类\n",
    "\n",
    "在实现单例之前，需要了解**使用 `type` 创造类**的方法，代码如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "do sth\n"
     ]
    }
   ],
   "source": [
    "def func(self):\n",
    "    print(\"do sth\")\n",
    "\n",
    "Klass = type(\"Klass\", (), {\"func\": func})\n",
    "\n",
    "c = Klass()\n",
    "c.func()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上，我们使用 type 创造了一个类出来。这里的知识是 mataclass 实现单例的基础。\n",
    "\n",
    "### 实现单例模式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "Foo1\n",
      "True\n",
      "Faa1\n"
     ]
    }
   ],
   "source": [
    "# Method 1\n",
    "import threading\n",
    "\n",
    "\n",
    "class SingletonType(type):\n",
    "    _instance_lock = threading.Lock()\n",
    "\n",
    "    def __call__(cls, *args, **kwargs):\n",
    "        if not hasattr(cls, \"_instance\"):\n",
    "            with SingletonType._instance_lock:\n",
    "                if not hasattr(cls, \"_instance\"):\n",
    "                    cls._instance = super(SingletonType,\n",
    "                                          cls).__call__(*args, **kwargs)\n",
    "        return cls._instance\n",
    "\n",
    "\n",
    "class Foo(metaclass=SingletonType):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "\n",
    "obj1 = Foo('Foo1')\n",
    "obj2 = Foo('Foo2')\n",
    "print(obj1 is obj2)\n",
    "print(obj2.name)\n",
    "\n",
    "\n",
    "# 可以应用到多个单例中\n",
    "class Faa(metaclass=SingletonType):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "\n",
    "obj1 = Faa('Faa1')\n",
    "obj2 = Faa('Faa2')\n",
    "print(obj1 is obj2)\n",
    "print(obj2.name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "# Method 2\n",
    "\n",
    "class Singleton(type):\n",
    "    _instances = {}\n",
    "\n",
    "    def __call__(cls, *args, **kwargs):\n",
    "        if cls not in cls._instances:\n",
    "            cls._instances[cls] = super(Singleton,\n",
    "                                        cls).__call__(*args, **kwargs)\n",
    "        return cls._instances[cls]\n",
    "\n",
    "\n",
    "class Cls4(metaclass=Singleton):\n",
    "    pass\n",
    "\n",
    "\n",
    "cls1 = Cls4()\n",
    "cls2 = Cls4()\n",
    "print(id(cls1) == id(cls2))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "212.352px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
